function MVVM(options) {
    //options配置项 : {el,data,....}
    //this:vm实例对象
    this.$options = options;
    //拿出data数据 (当前函数可以通过data变量来访问data数据)
    //拿出data数据 (MVVM原型上注册的方法可以通过_data数据来访问data数据)
    var data = this._data = this.$options.data;
    //this劫持  在后续代码中this可能会丢失;这时我们可以使用me来代替
    var me = this;

    //Object.keys(data): 返回data的所有可枚举属性名(enumerable:true)组成的数组
    Object.keys(data).forEach(function(key) {
        //key:data中的每一个属性名
        me._proxy(key);
    });

    // 数据劫持
    // data:data数据
    // this:vm实例对象
    observe(data, this);

    //模板解析
    this.$compile = new Compile(options.el || document.body, this)
}

MVVM.prototype = {
    $watch: function(key, cb, options) {
        new Watcher(this, key, cb);
    },

    //key:data中的每一个属性名
    _proxy: function(key) {
        //this劫持  this:vm实例对象
        var me = this;
        Object.defineProperty(me, key, {
            configurable: false,
            enumerable: true,

            //通过vm实例对象对data中的数据发起访问时触发
            get: function proxyGetter() {
                return me._data[key];
            },

            //通过vm实例对象对data中的数据发起修改时触发;newVal:修改完最新的值
            set: function proxySetter(newVal) {
                // 改的是data配置中的数据
                // 当data中的数据产生改变时 不可能只执行下述一行代码
                // 必定触发了很多其他回调!!!(跟数据劫持有关)
                me._data[key] = newVal;
            }
        });
    }
};